package module.map.nodes
{
	import drongo.desktop.selector.SelectorEvent;
	import drongo.desktop.utils.CollisionsHelp;
	import drongo.model.core.IProperty;
	import drongo.model.events.ModelEvent;
	import drongo.model.propertys.ArrayProperty;
	import drongo.model.values.CollectionValue;

	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.ui.Keyboard;
	import flash.utils.getTimer;

	import common.view.FGUIMediator;

	import module.map.Operations;
	import module.map.model.MapModel;
	import module.map.model.ProjectModel;
	import module.map.model.Propertys;
	import module.map.operations.propertys.datas.ArrayPropertyChangeData;
	import module.map.operations.propertys.datas.PropertyChangeData;
	import module.map.utils.PathUtils;

	import robotlegs.bender.extensions.mediatorMap.api.IMediatorMap;

	import ui.Map.UI_PathNodeView;
	import ui.Map.UI_PointView;
	import drongo.model.propertys.NumberProperty;

	/**
	 * 路径节点
	 */
	public class PathNodeMediator extends FGUIMediator
	{
		[Inject]
		public var project:ProjectModel;
		[Inject]
		public var view:UI_PathNodeView;

		[Inject]
		public var mediatorMap:IMediatorMap;

		private var currentMap:MapModel;
		private var nodes:ArrayProperty;
		private var nodeData:CollectionValue;
		private var points:ArrayProperty;
		private var pointViews:Array;

		private var stage:Stage;

		private static var viewStartPoint:Point = new Point();
		private static var startPoint:Point = new Point();
		private static var endPoint:Point = new Point();

		private static var lastPoint:Point = new Point();
		private static var lastPointValue:CollectionValue;
		private static var currentPoint:Point = new Point();
		private static var currentPointValue:CollectionValue;

		private static var tempPoint0:Point = new Point();

		private static var pathEgde:Vector.<Number>;

		/**
		 * 向量列表
		 */
		private var vectorList:Vector.<Number> = new Vector.<Number>();
		public function PathNodeMediator()
		{
			super();
		}
		override public function initialize():void
		{
			super.initialize();
			this.pointViews = [];
			this.stage = this.view.displayObject.stage;
			this.currentMap = this.project.currentMap;
			this.nodes = this.currentMap.Get(Propertys.NODES) as ArrayProperty;
			this.nodeData = this.view.data as CollectionValue;
			// 数据验证
			if (this.nodeData.Get(Propertys.COUNT) == null)
			{
				this.nodeData.Add(new NumberProperty(Propertys.COUNT, 3));
			}
			this.points = this.nodeData.Get(Propertys.POINTS) as ArrayProperty;

			// 边缘点集合
			pathEgde = new Vector.<Number>();

			this.RefreshView();
			this.RefreshPoints();
			this.AddEvents();
		}

		override public function destroy():void
		{
			super.destroy();
			RemoveEvents();
		}

		protected function AddEvents():void
		{
			this.nodeData.addEventListener(ModelEvent.CHILD_VALUE_CHANGED, this.NodeDataChanged);
			this.points.addEventListener(ModelEvent.CHILD_VALUE_CHANGED, this.PointsUpdateHandler);
			this.points.addEventListener(ModelEvent.ADD_CHILD, this.PointsUpdateHandler);
			this.points.addEventListener(ModelEvent.REMOVE_CHILD, this.PointsUpdateHandler);

			this.view.addEventListener(MouseEvent.MOUSE_DOWN, this.DragMouseDownHandler);
			this.stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyboardDownHandler);
			this.currentMap.selector.addEventListener(SelectorEvent.SELECTLIST_CHANGE, this.SelectListChanged);

			this.stage.addEventListener(Event.ENTER_FRAME, this.Tick);
		}

		protected function RemoveEvents():void
		{
			this.nodeData.removeEventListener(ModelEvent.CHILD_VALUE_CHANGED, this.NodeDataChanged);
			this.points.removeEventListener(ModelEvent.CHILD_VALUE_CHANGED, this.PointsUpdateHandler);
			this.points.removeEventListener(ModelEvent.ADD_CHILD, this.PointsUpdateHandler);
			this.points.removeEventListener(ModelEvent.REMOVE_CHILD, this.PointsUpdateHandler);

			this.view.removeEventListener(MouseEvent.MOUSE_DOWN, this.DragMouseDownHandler);
			this.stage.removeEventListener(MouseEvent.MOUSE_MOVE, this.DragMouseMoveHandler);
			this.stage.removeEventListener(MouseEvent.MOUSE_UP, this.DragMouseUpHandler);
			this.stage.removeEventListener(KeyboardEvent.KEY_DOWN, KeyboardDownHandler);
			this.currentMap.selector.removeEventListener(SelectorEvent.SELECTLIST_CHANGE, this.SelectListChanged);

			this.stage.removeEventListener(Event.ENTER_FRAME, this.Tick);
		}

		private function RefreshView():void
		{
			this.view.x = nodeData.Get(Propertys.X).GetValue();
			this.view.y = nodeData.Get(Propertys.Y).GetValue();
			this.DrawBackground();
			this.DrawSelected();
			this.view.visible = this.nodeData.Get(Propertys.VISIBLE).GetValue() > 0;
			this.view.touchable = this.nodeData.Get(Propertys.LOCK).GetValue() == 0;
		}

		private function SelectListChanged(e:SelectorEvent):void
		{
			this.RefreshView();
		}

		private function PointsUpdateHandler(e:ModelEvent):void
		{
			this.CallNextFrame(this.RefreshPoints);
		}

		private function RefreshPoints():void
		{
			// 清理老的
			var pointView:UI_PointView;
			for (var i:int = 0; i < this.pointViews.length; i++)
			{
				pointView = this.pointViews[i];
				pointView.removeFromParent();
				mediatorMap.unmediate(pointView);
			}
			var count:uint = this.points.length;
			var pointData:CollectionValue;
			for (var index:int = 0; index < count; index++)
			{
				pointView = UI_PointView.createInstance();
				pointData = this.points.GetAt(index) as CollectionValue;
				pointView.data = {node: this.nodeData, point: pointData};
				this.pointViews.push(pointView);
				this.view.addChild(pointView);
				mediatorMap.mediate(pointView);
			}
			this.DrawPath();
		}

		/**
		 * 绘制背景
		 */
		private function DrawBackground():void
		{
			this.view.m_background.graphics.clear();
			if (ediatorMode)
			{
				this.view.m_background.graphics.beginFill(0x000000, 0.5);
				this.view.m_background.graphics.drawRect(-30000, -30000, 60000, 60000);
			}
		}

		private function DrawSelected():void
		{
			this.view.m_selectLayer.graphics.clear();
			this.view.m_selectLayer.graphics.lineStyle(4, 0xFFFF00);
			var index:int = this.project.currentMap.selector.selectedList.indexOf(this.nodeData);
			if (index >= 0)
			{
				var currentPointData:CollectionValue;
				var lineCommands:Vector.<int> = new Vector.<int>();
				var lineData:Vector.<Number> = new Vector.<Number>();
				var count:uint = this.points.length;
				for (var i:int = 0; i < count; i++)
				{
					currentPointData = this.points.GetAt(i) as CollectionValue;
					// 绘制
					if (i == 0)
					{
						lineCommands.push(1);
					}
					else
					{
						lineCommands.push(2);
					}
					currentPoint.x = currentPointData.Get(Propertys.X).GetValue();
					currentPoint.y = currentPointData.Get(Propertys.Y).GetValue();
					lineData.push(currentPoint.x, currentPoint.y);
				}
				// 连线
				this.view.m_selectLayer.graphics.drawPath(lineCommands, lineData);
			}
		}

		private function DrawPath():void
		{
			this.view.m_lineLayer.graphics.clear();
			this.view.m_lineLayer.graphics.lineStyle(3, 0x00FF00);

			this.view.m_fillLayer.graphics.clear();
			this.view.m_fillLayer.graphics.lineStyle(1, 0x00FF00);
			this.view.m_fillLayer.graphics.beginFill(0x00FFCC, 0.5);
			
			var count:Number = this.nodeData.Get(Propertys.COUNT).GetValue();
			var list:Array = [];
			var x:Number = this.nodeData.Get(Propertys.X).GetValue();
			var y:Number = this.nodeData.Get(Propertys.Y).GetValue();
			PathUtils.GetPath2(this.nodeData, 0, 0, list, 3, false);
			for (var index:int = 0; index < list.length; index++)
			{
				var path:Array = list[index];
				this.view.m_lineLayer.graphics.moveTo(path[0] - x, path[1] - y);
				for (var i:Number = 2; i < path.length; i += 2)
				{
					this.view.m_lineLayer.graphics.lineTo(path[i] - x, path[i + 1] - y);
				}
			}
		}

		private function KeyboardDownHandler(e:KeyboardEvent):void
		{
			if (e.keyCode == Keyboard.ESCAPE)
			{
				if (ediatorMode)
				{
					this.nodeData.Update(Propertys.EDIATRO_MODE, 0);
				}
			}
			else if (e.keyCode == Keyboard.DELETE)
			{
				if (ediatorMode)
				{
					if (this.project.currentMap.selector.selectedList.length > 0)
					{
						this.project.undoSystem.executeOperation(Operations.REMOVE_POINT, {node: this.nodeData});
						this.project.currentMap.selector.resetSelectList();
					}
				}
			}
		}

		protected function NodeDataChanged(e:ModelEvent):void
		{
			var property:IProperty = e.newValue as IProperty;
			var key:String = property.GetKey();
			switch (key)
			{
				case Propertys.Y:
				case Propertys.X:
				{
					this.CallNextFrame(this.NodePositionChanged);
					break;
				}
				case Propertys.VISIBLE:
				case Propertys.LOCK:
				{
					this.CallNextFrame(this.RefreshView);
					break;
				}
				case Propertys.EDIATRO_MODE:
				{
					this.CallNextFrame(this.EdiatorModeChanged);
					break;
				}
				default:
				{
					break;
				}
			}
		}

		private function NodePositionChanged():void
		{
			this.view.x = this.nodeData.Get(Propertys.X).GetValue();
			this.view.y = this.nodeData.Get(Propertys.Y).GetValue();
		}

		private function EdiatorModeChanged():void
		{
			var ediatorMode:uint = this.nodeData.Get(Propertys.EDIATRO_MODE).GetValue();
			if (ediatorMode > 0)
			{
				this.view.parent.addChildAt(this.view, this.view.parent.numChildren - 1);
			}
			else
			{

			}
			this.DrawBackground();
		}

		private var lastMouseDownTime:int = 0;

		protected function DragMouseDownHandler(e:MouseEvent):void
		{
			e.stopImmediatePropagation();
			e.stopPropagation();
			// 编辑模式下
			if (ediatorMode)
			{
				var mousePoint:Point = this.view.globalToLocal(this.stage.mouseX, this.stage.mouseY);
				// 如果点在点上了
				if (CheckPoint(mousePoint))
				{
					return;
				}
				// 点在线上
				if (this.CheckMouse(mousePoint))
				{
					this.project.undoSystem.executeOperation(Operations.ADD_POINT, {node: nodeData, lastPoint: lastPointValue, currentPoint: currentPointValue, mousePoint: mousePoint});
				}
				else
				{
					this.project.undoSystem.executeOperation(Operations.ADD_POINT, {node: nodeData, mousePoint: mousePoint});
				}
				return;
			}
			// 拖拽处理
			var currentTime:int = getTimer();
			if (currentTime - lastMouseDownTime < 300)
			{
				this.stage.removeEventListener(MouseEvent.MOUSE_MOVE, this.DragMouseMoveHandler);
				this.stage.removeEventListener(MouseEvent.MOUSE_UP, this.DragMouseUpHandler);
				this.MouseDoubleClick(e);
				return;
			}
			lastMouseDownTime = currentTime;

			this.stage.addEventListener(MouseEvent.MOUSE_MOVE, this.DragMouseMoveHandler);
			this.stage.addEventListener(MouseEvent.MOUSE_UP, this.DragMouseUpHandler);
			viewStartPoint.x = this.view.x;
			viewStartPoint.y = this.view.y;

			startPoint.x = this.stage.mouseX;
			startPoint.y = this.stage.mouseY;

			// 不是多选
			if (!e.shiftKey)
			{
				this.project.currentMap.selector.resetSelectList();
			}
			if (this.project.currentMap.selector.selectedList.indexOf(this.nodeData) < 0)
			{
				this.project.currentMap.selector.push(this.nodeData);
			}
		}

		protected function MouseDoubleClick(e:MouseEvent):void
		{
			this.project.currentMap.selector.resetSelectList();
			if (this.project.currentMap.selector.selectedList.indexOf(this.nodeData) < 0)
			{
				this.project.currentMap.selector.push(this.nodeData);
			}
			this.nodeData.Update(Propertys.EDIATRO_MODE, 1);
		}

		protected function DragMouseMoveHandler(e:MouseEvent):void
		{
			e.stopImmediatePropagation();
			e.stopPropagation();
			endPoint.x = this.stage.mouseX;
			endPoint.y = this.stage.mouseY;

			this.view.x = viewStartPoint.x + (endPoint.x - startPoint.x);
			this.view.y = viewStartPoint.y + (endPoint.y - startPoint.y);
		}

		protected function DragMouseUpHandler(e:MouseEvent):void
		{
			e.stopImmediatePropagation();
			e.stopPropagation();
			this.stage.removeEventListener(MouseEvent.MOUSE_MOVE, this.DragMouseMoveHandler);
			this.stage.removeEventListener(MouseEvent.MOUSE_UP, this.DragMouseUpHandler);

			endPoint.x = this.stage.mouseX;
			endPoint.y = this.stage.mouseY;
			if (CollisionsHelp.DistanceDetection(startPoint, endPoint, 2))
			{
				return;
			}
			this.view.x = viewStartPoint.x + (endPoint.x - startPoint.x);
			this.view.y = viewStartPoint.y + (endPoint.y - startPoint.y);

			var selectList:Array = this.project.currentMap.selector.selectedList;
			if (selectList.length == 0)
			{
				throw new Error("没有选择的内容！");
			}
			var arrayChangeData:ArrayPropertyChangeData;
			var changeDataList:Vector.<PropertyChangeData>;
			// 老的属性
			var oldPropertys:Vector.<ArrayPropertyChangeData> = new Vector.<ArrayPropertyChangeData>();
			var nodeData:CollectionValue;
			for each (nodeData in selectList)
			{
				changeDataList = new Vector.<PropertyChangeData>();
				changeDataList.push(
						new PropertyChangeData(Propertys.X, nodeData.Get(Propertys.X).GetValue()),
						new PropertyChangeData(Propertys.Y, nodeData.Get(Propertys.Y).GetValue())
					);
				arrayChangeData = new ArrayPropertyChangeData(
						Propertys.ID,
						nodeData.Get(Propertys.ID).GetValue(),
						changeDataList
					);
				oldPropertys.push(arrayChangeData);
			}
			// 新的属性值
			var newPropertys:Vector.<ArrayPropertyChangeData> = new Vector.<ArrayPropertyChangeData>();
			for each (nodeData in selectList)
			{
				changeDataList = new Vector.<PropertyChangeData>();
				changeDataList.push(
						new PropertyChangeData(Propertys.X, nodeData.Get(Propertys.X).GetValue() + (endPoint.x - startPoint.x)),
						new PropertyChangeData(Propertys.Y, nodeData.Get(Propertys.Y).GetValue() + (endPoint.y - startPoint.y))
					);
				arrayChangeData = new ArrayPropertyChangeData(
						Propertys.ID,
						nodeData.Get(Propertys.ID).GetValue(),
						changeDataList
					);
				newPropertys.push(arrayChangeData);
			}

			this.project.undoSystem.executeOperation(Operations.ARRAY_PROPERTYS_CHANGE, {parent: this.nodes, oldPropertys: oldPropertys, newPropertys: newPropertys});
		}

		/**
		 * 检测鼠标与各点是否相近
		 */
		private function CheckPoint(mousePoint:Point, disMin:Number = 10):Boolean
		{
			var pointView:UI_PointView;
			for (var i:int = 0; i < this.pointViews.length; i++)
			{
				pointView = this.pointViews[i];
				tempPoint0.x = pointView.x;
				tempPoint0.y = pointView.y;
				// 距离要开平方，这里用距离的平方代替
				if (CollisionsHelp.DistanceDetection(mousePoint, tempPoint0, disMin))
				{
					return true;
				}
			}
			return false;
		}

		/**
		 * 检测鼠标点是否在线上
		 * @param mouse				鼠标位置
		 * @param distMin			最小距离
		 * @return
		 */
		private function CheckMouse(mouse:Point, distMin:Number = 5):Boolean
		{
			var dataLen:uint = this.points.length;
			var dist:Number;
			for (var i:int = 0; i < dataLen; i++)
			{
				currentPointValue = this.points.GetAt(i) as CollectionValue;
				if (i > 0)
				{
					lastPointValue = this.points.GetAt(i - 1) as CollectionValue;
					lastPoint.x = lastPointValue.Get(Propertys.X).GetValue();
					lastPoint.y = lastPointValue.Get(Propertys.Y).GetValue();
					currentPoint.x = currentPointValue.Get(Propertys.X).GetValue();
					currentPoint.y = currentPointValue.Get(Propertys.Y).GetValue();
					dist = CollisionsHelp.GetNearestDistance(mouse, lastPoint, currentPoint);
					// 在线段上
					if (dist < distMin)
					{
						return true;
					}
				}
			}
			return false;
		}

		private function get ediatorMode():Boolean
		{
			var mode:uint = this.nodeData.Get(Propertys.EDIATRO_MODE).GetValue();
			return mode > 0 ? true : false;
		}
	}
}